package com.tantinevincent.vector;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.tantinevincent.parser.dynamic_length.ReferenceLength;

public class DynamicSparseVector implements IVector{
	/**
	 * the length of vector.
	 */
	private ReferenceLength refLength;
	/**
	 * this hash map save index and value in every entry.
	 */
	private Map<Integer,Double> map = new HashMap<Integer,Double>();
	/**
	 * Initialize the vector by length.
	 * @param refLength the dynamic length of vector.
	 */
	public DynamicSparseVector(ReferenceLength refLength){
		this.refLength = refLength;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int length() {
		return refLength.getLength();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int[] getIndices() {
		// Get all index in hash map
		Set<Integer> indexSet = map.keySet();
		// put all index in array
		int i = 0;
		int[] indices = new int[ indexSet.size() ];
		for( int index : indexSet ){
			indices[i] = index;
			i++;
		}
		// sorting to ascending integer array.
		Arrays.sort(indices);
		return indices;
	}

	/**
	 * Set value to vector in the index position.
	 * @param index the index of value where you set.
	 * @param value the value which you set.
	 */
	public void set(int index, double value) {
		if( value == 0.0 ){
			return;  // the zero value dosen't need to saved.
		}
		if( isInRange(index) ){  // not in range
			throwIndexOutOfRangeException();
			return;
		}
		if( contains(index) ){
			map.remove(index);
		}
		map.put(index, value);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public double get(int index) {
		if( isInRange(index) ){  // not in range
			throwIndexOutOfRangeException();
			return Double.NaN;
		}
		if( !contains(index) ){
			return 0.0;
		}
		return map.get(index);
	}
	/**
	 * Check the index is exist or not.
	 * @param index the index of vector..
	 * @return the vector is exist or not.
	 */
	public boolean contains(int index){
		return map.containsKey( index );
	}
	/**
	 * Throw index out of range. That's it.
	 */
	private void throwIndexOutOfRangeException(){
		try {
			throw new Exception( "Index out of range." );
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}
	/**
	 * Check the index is in vector's range or not
	 */
	private boolean isInRange(int index){
		return index < 0 || index > refLength.getLength()-1;
	}
}
